﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Collections;
using System.Windows.Media;

namespace Relay.UI.Controls.Docking {
    /// <summary>
    /// Represents a collection of FrameworkElement objects which is directly
    /// tied to the host control's child collection.
    /// </summary>
    public class BoundFrameworkElementCollection : IList<FrameworkElement>, IList {
        #region Fields
        private IFrameworkElementHost _host = null;
        private readonly Type[] _types = null;
        private readonly List<FrameworkElement> _list = new List<FrameworkElement>();
        #endregion

        #region Constructor
        internal BoundFrameworkElementCollection(IFrameworkElementHost host, Type[] validTypes) {
            _host = host;
            _types = validTypes;
        }
        #endregion

        #region Private Members
        private void AddToParent(FrameworkElement element) {
            _host.AddChild(element);
        }

        private void RemoveFromParent(FrameworkElement element) {
            _host.RemoveChild(element);
        }

        private void ValidateType(FrameworkElement element) {
            if (element == null)
                throw new ArgumentNullException("element");

            if (!_types.Contains(element.GetType()))
                throw new ArgumentException("Attempted to add an invalid object to a FrameworkElementCollection.");
        }
        #endregion

        #region IList<FrameworkElement> Members
        public int IndexOf(FrameworkElement item) {
            return _list.IndexOf(item);
        }

        public void Insert(int index, FrameworkElement item) {
            ValidateType(item);
            AddToParent(item);
            _list.Insert(index, item);
        }

        public void RemoveAt(int index) {
            _list.RemoveAt(index);
            RemoveFromParent(_list[index]);            
        }

        public FrameworkElement this[int index] {
            get {
                return _list[index];
            }
            set {
                throw new NotImplementedException();
            }
        }
        #endregion

        #region ICollection<FrameworkElement> Members
        public void Add(FrameworkElement item) {
            ValidateType(item);
            AddToParent(item);
            _list.Add(item);
        }

        public void Clear() {
            List<FrameworkElement> temp = _list.ToList();
            _list.Clear();

            foreach (FrameworkElement element in temp)
                RemoveFromParent(element);
        }

        public bool Contains(FrameworkElement item) {
            return _list.Contains(item);
        }

        public void CopyTo(FrameworkElement[] array, int arrayIndex) {
            _list.CopyTo(array, arrayIndex);
        }

        public int Count {
            get { return _list.Count; }
        }

        public bool IsReadOnly {
            get { return false; }
        }

        public bool Remove(FrameworkElement item) {
            bool r = _list.Remove(item);
            RemoveFromParent(item);
            return r;
        }
        #endregion

        #region IEnumerable<FrameworkElement> Members
        public IEnumerator<FrameworkElement> GetEnumerator() {
            return _list.GetEnumerator();
        }
        #endregion

        #region IEnumerable Members
        IEnumerator IEnumerable.GetEnumerator() {
            return _list.GetEnumerator();
        }
        #endregion

        #region IList Members
        int IList.Add(object value) {
            Add((FrameworkElement)value);
            return _list.Count - 1;
        }

        void IList.Clear() {
            Clear();
        }

        bool IList.Contains(object value) {
            return Contains((FrameworkElement)value);
        }

        int IList.IndexOf(object value) {
            return IndexOf((FrameworkElement)value);
        }

        void IList.Insert(int index, object value) {
            Insert(index, (FrameworkElement)value);
        }

        bool IList.IsFixedSize {
            get { return false; }
        }

        bool IList.IsReadOnly {
            get { return false; }
        }

        void IList.Remove(object value) {
            Remove((FrameworkElement)value);
        }

        void IList.RemoveAt(int index) {
            RemoveAt(index);
        }

        object IList.this[int index] {
            get {
                return (FrameworkElement)this[index];
            }
            set {
                throw new NotImplementedException();
            }
        }
        #endregion

        #region ICollection Members
        void ICollection.CopyTo(Array array, int index) {
            ((ICollection)_list).CopyTo(array, index);
        }

        int ICollection.Count {
            get { return _list.Count; }
        }

        bool ICollection.IsSynchronized {
            get { return false; }
        }

        object ICollection.SyncRoot {
            get { return ((ICollection)_list).SyncRoot; }
        }
        #endregion
    }
}
